/**
 * 
 */
package com.pxingg.utils;

import java.io.IOException;

import com.pxingg.exception.XException;

/**
 * 定义一个二进制到ASCII字符的转换的方法集合
 * 
 * @author pxingg
 * 
 */
public class HexStringUtils
{
    /**
     * 一个字节到16进制字符的映射表
     */
    public static final String[] BYTE_HEX_MAP = {
        "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31", "32", "33",
        "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67",
        "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B",
        "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
        "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
    };

    /**
     * 一个字节对应的ASCII字符的映射表
     */
    public static final String[] BYTE_PRINT_MAP = {
        ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=",
        ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\"", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{",
        "|", "}", "~", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",
        ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".", ".",
        ".", ".", ".", ".", ".", ".", ".", "."
    };

    /**
     * 把一个byte[]数组的字符转换成HEX字符串,HEX字节之间使用指定的分隔符来填充
     * 
     * @param data
     *            字节流数组
     * @param sperator
     * @return 转换出来的字符串
     */
    public static String hex2String(final byte[] data, final String sperator)
    {
        return HexStringUtils.hex2String(data, sperator, 0, data.length);
    }

    /**
     * 把一个byte[]数组的字符转换成HEX字符串,HEX字节之间使用指定的分隔符来填充
     * 
     * @param data
     *            字节流数组
     * @param sperator
     *            一个字节之间的分割符
     * @param start
     *            起始字节位置
     * @param length
     *            需要打印的字符的长度
     * @return 转换出来的字符串
     */
    public static String hex2String(final byte[] data, final String sperator, final int start, final int length)
    {
        final StringBuffer sb = new StringBuffer();
        final int end = data.length > (start + length) ? (start + length) : data.length;
        for (int i = start; i < end; i++)
        {
            sb.append(HexStringUtils.BYTE_HEX_MAP[data[i] & 0xFF]);
            if (i != end - 1)
            {
                sb.append(sperator);
            }
        }

        return sb.toString();
    }

    /**
     * 把一个字节流中的ASCII字符转换成字符串，其中的不可打印字符用.来替换<br>
     * 输出的格式如下<br>
     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00 01 02 03 04 05 06 07-08 09 0A 0B 0C 0D 0E 0F -> 0123456789ABCDEF<br>
     * 0x00000020 20 21 22 23 24 25 26 27-28 29 2A 2B 2C 2D 2E 2F -> !"#$%&'()*+,-./<br>
     * 0x00000030 30 31 32 33 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -> 0123 <br>
     * 
     * @param data
     *            字节流数组
     * @param start
     *            起始字节位置
     * @param length
     *            需要打印的字符的长度
     * @return 转换出来的字符串
     */
    public static String hex2String2(final byte[] data, final int start, final int length)
    {
        final StringBuffer sb = new StringBuffer();
        final StringBuffer sbHex = new StringBuffer();
        final StringBuffer sbPrint = new StringBuffer();
        final int end = data.length > (start + length) ? (start + length) : data.length;
        final int endPrint = (end % 16 == 0) ? end : (end / 16 + 1) * 16;

        // 打印第一行字节索引字的值
        sb.append(String.format("%11s", " "));
        for (int i = 0; i < 16; i++)
        {
            sbHex.append(HexStringUtils.BYTE_HEX_MAP[i]);
            sbPrint.append(String.format("%X", i));
            if (i == 7)
            {
                sbHex.append('-');
            }
            else if (i == 15)
            {
                // 最后一个字节的后面不要跟空格
                ;
            }
            else
            {
                sbHex.append(' ');
            }
        }
        sb.append(sbHex.toString());
        sb.append(" -> ");
        sb.append(sbPrint.toString());
        sb.append('\n');
        sbHex.delete(0, sbHex.length());
        sbPrint.delete(0, sbPrint.length());

        for (int index = (start / 16) * 16; index < endPrint; index++)
        {
            if (index % 16 == 0)
            {
                // 输出字符串的位置
                sb.append(String.format("0x%08X ", index));
            }
            if (index < start || index >= end)
            {
                // 进行16字节对齐，没有的字符补空格
                sbHex.append("  ");
                sbPrint.append(' ');
            }
            else
            {
                sbHex.append(HexStringUtils.BYTE_HEX_MAP[data[index] & 0xFF]);
                sbPrint.append(HexStringUtils.BYTE_PRINT_MAP[data[index] & 0xFF]);
            }

            if (index % 16 == 7)
            {
                sbHex.append('-');
            }
            else if (index % 16 == 15)
            {
                // 最后一个字节的后面不要跟空格
                // 开始拼接输出的字符串
                sb.append(sbHex.toString());
                sb.append(" -> ");
                sb.append(sbPrint.toString());
                sb.append('\n');
                sbHex.delete(0, sbHex.length());
                sbPrint.delete(0, sbPrint.length());
            }
            else
            {
                sbHex.append(' ');
            }

        }

        return sb.toString();
    }

    public static void main(final String[] argv) throws IOException, XException
    {

        final byte data[] = {
            (byte) 0x0, (byte) 0x1, (byte) 0x2, (byte) 0x3, (byte) 0x4, (byte) 0x5, (byte) 0x6, (byte) 0x7, (byte) 0x8, (byte) 0x9, (byte) 0xA, (byte) 0xB, (byte) 0xC, (byte) 0xD, (byte) 0xE, (byte) 0xF, (byte) 0x10, (byte) 0x11, (byte) 0x12, (byte) 0x13, (byte) 0x14, (byte) 0x15, (byte) 0x16, (byte) 0x17,
            (byte) 0x18, (byte) 0x19, (byte) 0x1A, (byte) 0x1B, (byte) 0x1C, (byte) 0x1D, (byte) 0x1E, (byte) 0x1F, (byte) 0x20, (byte) 0x21, (byte) 0x22, (byte) 0x23, (byte) 0x24, (byte) 0x25, (byte) 0x26, (byte) 0x27, (byte) 0x28, (byte) 0x29, (byte) 0x2A, (byte) 0x2B, (byte) 0x2C, (byte) 0x2D, (byte) 0x2E,
            (byte) 0x2F, (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0x35, (byte) 0x36, (byte) 0x37, (byte) 0x38, (byte) 0x39, (byte) 0x3A, (byte) 0x3B, (byte) 0x3C, (byte) 0x3D, (byte) 0x3E, (byte) 0x3F, (byte) 0x40, (byte) 0x41, (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45,
            (byte) 0x46, (byte) 0x47, (byte) 0x48, (byte) 0x49, (byte) 0x4A, (byte) 0x4B, (byte) 0x4C, (byte) 0x4D, (byte) 0x4E, (byte) 0x4F, (byte) 0x50, (byte) 0x51, (byte) 0x52, (byte) 0x53, (byte) 0x54, (byte) 0x55, (byte) 0x56, (byte) 0x57, (byte) 0x58, (byte) 0x59, (byte) 0x5A, (byte) 0x5B, (byte) 0x5C,
            (byte) 0x5D, (byte) 0x5E, (byte) 0x5F, (byte) 0x60, (byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64, (byte) 0x65, (byte) 0x66, (byte) 0x67, (byte) 0x68, (byte) 0x69, (byte) 0x6A, (byte) 0x6B, (byte) 0x6C, (byte) 0x6D, (byte) 0x6E, (byte) 0x6F, (byte) 0x70, (byte) 0x71, (byte) 0x72, (byte) 0x73,
            (byte) 0x74, (byte) 0x75, (byte) 0x76, (byte) 0x77, (byte) 0x78, (byte) 0x79, (byte) 0x7A, (byte) 0x7B, (byte) 0x7C, (byte) 0x7D, (byte) 0x7E, (byte) 0x7F, (byte) 0x80, (byte) 0x81, (byte) 0x82, (byte) 0x83, (byte) 0x84, (byte) 0x85, (byte) 0x86, (byte) 0x87, (byte) 0x88, (byte) 0x89, (byte) 0x8A,
            (byte) 0x8B, (byte) 0x8C, (byte) 0x8D, (byte) 0x8E, (byte) 0x8F, (byte) 0x90, (byte) 0x91, (byte) 0x92, (byte) 0x93, (byte) 0x94, (byte) 0x95, (byte) 0x96, (byte) 0x97, (byte) 0x98, (byte) 0x99, (byte) 0x9A, (byte) 0x9B, (byte) 0x9C, (byte) 0x9D, (byte) 0x9E, (byte) 0x9F, (byte) 0xA0, (byte) 0xA1,
            (byte) 0xA2, (byte) 0xA3, (byte) 0xA4, (byte) 0xA5, (byte) 0xA6, (byte) 0xA7, (byte) 0xA8, (byte) 0xA9, (byte) 0xAA, (byte) 0xAB, (byte) 0xAC, (byte) 0xAD, (byte) 0xAE, (byte) 0xAF, (byte) 0xB0, (byte) 0xB1, (byte) 0xB2, (byte) 0xB3, (byte) 0xB4, (byte) 0xB5, (byte) 0xB6, (byte) 0xB7, (byte) 0xB8,
            (byte) 0xB9, (byte) 0xBA, (byte) 0xBB, (byte) 0xBC, (byte) 0xBD, (byte) 0xBE, (byte) 0xBF, (byte) 0xC0, (byte) 0xC1, (byte) 0xC2, (byte) 0xC3, (byte) 0xC4, (byte) 0xC5, (byte) 0xC6, (byte) 0xC7, (byte) 0xC8, (byte) 0xC9, (byte) 0xCA, (byte) 0xCB, (byte) 0xCC, (byte) 0xCD, (byte) 0xCE, (byte) 0xCF,
            (byte) 0xD0, (byte) 0xD1, (byte) 0xD2, (byte) 0xD3, (byte) 0xD4, (byte) 0xD5, (byte) 0xD6, (byte) 0xD7, (byte) 0xD8, (byte) 0xD9, (byte) 0xDA, (byte) 0xDB, (byte) 0xDC, (byte) 0xDD, (byte) 0xDE, (byte) 0xDF, (byte) 0xE0, (byte) 0xE1, (byte) 0xE2, (byte) 0xE3, (byte) 0xE4, (byte) 0xE5, (byte) 0xE6,
            (byte) 0xE7, (byte) 0xE8, (byte) 0xE9, (byte) 0xEA, (byte) 0xEB, (byte) 0xEC, (byte) 0xED, (byte) 0xEE, (byte) 0xEF, (byte) 0xF0, (byte) 0xF1, (byte) 0xF2, (byte) 0xF3, (byte) 0xF4, (byte) 0xF5, (byte) 0xF6, (byte) 0xF7, (byte) 0xF8, (byte) 0xF9, (byte) 0xFA, (byte) 0xFB, (byte) 0xFC, (byte) 0xFD,
            (byte) 0xFE, (byte) 0xFF
        };

        System.out.println(HexStringUtils.hex2String(data, " ", 2, 2));
        System.out.println(HexStringUtils.hex2String2(data, 32, 20));

        System.out.println(HexStringUtils.string2Hex("30C")[0]);

    }

    /**
     * 把16进制字符串(格式A1B1A2B2...)转换成二进制的数字
     * 
     * @param hexString
     *            hex的字符串
     * @return 字节数组
     * @throws XException
     *             输入字符串非法
     */
    public static byte[] string2Hex(final String hexString) throws XException
    {
        final int length = hexString.getBytes().length;
        if (length % 2 != 0)
        {
            throw new XException("the length of hex string is error, " + hexString);
        }

        final byte[] data = hexString.toUpperCase().getBytes();

        final int byteLenth = length / 2;
        final byte[] result = new byte[byteLenth];
        int index = 0;
        for (int i = 0; i < byteLenth; i++)
        {
            int bitHigh = data[index++] - '0';
            if (bitHigh > 0x09)
            {
                bitHigh -= 7;
            }

            if (bitHigh > 0x0F)
            {
                throw new XException("hex string is invalid, " + hexString);
            }

            int bitLow = data[index++] - '0';
            if (bitLow > 0x09)
            {
                bitLow -= 7;
            }

            if (bitLow > 0x0F)
            {
                throw new XException("hex string is invalid," + hexString);
            }

            result[i] = (byte) ((bitHigh << 4) + bitLow);

        }

        return result;
    }

    /**
     * 把16进制字符串(格式A1B1[separator]A2B2...AnBn)转换成二进制的数字(注意，这里最后一个16进制字符串后没有分割符号)
     * 
     * @param hexString
     *            hex的字符串
     * @return 字节数组
     * @throws XException
     *             输入字符串非法
     */
    public static byte[] string2Hex(final String hexString, final String seperator) throws XException
    {
        final int length = hexString.getBytes().length;
        final int seperatorLength = seperator.getBytes().length;
        final byte[] data = hexString.toUpperCase().getBytes();

        if ((length - 2) % (2 + seperatorLength) != 0 || length < 2)
        {
            throw new XException("the length of hex string is error," + hexString);
        }

        final int byteLenth = (length - 2) / (2 + seperatorLength) + 1;
        final byte[] result = new byte[byteLenth];
        int index = 0;
        for (int i = 0; i < byteLenth; i++)
        {
            int bitHigh = data[index++] - '0';
            if (bitHigh > 0x09)
            {
                bitHigh -= 7;
            }

            if (bitHigh > 0x0F)
            {
                throw new XException("hex string is invalid," + hexString);
            }

            int bitLow = data[index++] - '0';
            if (bitLow > 0x09)
            {
                bitLow -= 7;
            }

            if (bitLow > 0x0F)
            {
                throw new XException("hex string is invalid," + hexString);
            }

            result[i] = (byte) ((bitHigh << 4) + bitLow);

            // 跳过指定的分隔符
            index += seperatorLength;

        }

        return result;
    }
}
